
from mpdiface import Attrs
from songutils import *
import random
from draw import pcentred, clrline
import conf
from curses import A_NORMAL, A_BOLD

# Todo: none of these are implemented, or the setting's ignored and it always
# adds stuff to the end like STOP_NEVER
STOP_NEVER       = 1       # Keep adding new tracks when the playlist
                           # is exhausted so as to keep it going
STOP_AFTER_TRACK = 2       # Stop after each track played
STOP_AFTER_QUEUE = 3       # Stop after the playlist is finished

def stopmodestr(stopmode):
    d = {
        STOP_NEVER: "STOP_NEVER",
        STOP_AFTER_TRACK: "STOP_AFTER_TRACK",
        STOP_AFTER_QUEUE: "STOP_AFTER_QUEUE"
        }
    return d.get(stopmode, "BUG: Unknown stopmode")

def playcount_to_string(n):
    if n == 0:
        return "not played"
    elif n == 1:
        return "played once"
    elif n == 2:
        return "played twice"
    else:
        return "played %d times" % n

class Controller:
    def __init__(self, client):
        self.__client = client
        self.stopmode = STOP_NEVER
        self.library = [Attrs(song) for song in self.__client.listallinfo() if issong(Attrs(song))]
        for song in self.library:
            song.playcount = 0
        self.prevsong = None
        self.last_search_string = None
        self.last_search_results = []

    def tick(self):
        try:
            status = self.status()
            songsleft = int(status.playlistlength) - int(status.song)
            if songsleft <= 1:
                self.dj()
        except AttributeError:
            # probably empty playlist
            self.dj()

    def songchangehook(self, song):
        s = songrepr(song)
        for l in self.library:
            if songrepr(l) == s:
                l.playcount += 1
                break

    # this is called when it's safe to update the screen
    def dj(self):
        minplaycount = min([song.playcount for song in self.library])

        # don't pick the same song
        if self.prevsong is not None:
            candidates = [song for song in self.library if song.playcount == minplaycount and songrepr(song) != songrepr(self.prevsong)]
        else:
            candidates = [song for song in self.library if song.playcount == minplaycount]

        # todo: improve selection to not play the same artist in a row maybe
        selected = random.choice(candidates)
        pcentred(conf.L_DJ_MESSAGE,
                 (A_NORMAL, "DJing... selected "),
                 (A_BOLD, songrepr(selected)),
                 (A_NORMAL, " (%s)" % playcount_to_string(selected.playcount)))

        # for long titles that spill over, truncate rather than leave a line
        clrline(conf.L_DJ_MESSAGE+1)
        self.playlater(selected)

    def next(self):
        self.__client.next()

    def prev(self):
        self.__client.previous()

    def pause(self):
        self.__client.pause()

    def stop(self):
        self.__client.stop()

    def play(self):
        self.__client.play()

    def status(self):
        return Attrs(self.__client.status())

    def currentsong(self):
        if self.__client.status()['state'] != 'play':
            return None
        cursong = Attrs(self.__client.currentsong())
        if (self.prevsong is None and cursong is not None) or cursong.file != self.prevsong.file:
            self.prevsong = cursong
            self.songchangehook(cursong)
        return cursong

    def nextsong(self):
        cur = self.currentsong()
        playlist = self.__client.playlistinfo()
        if not playlist:
            return None
        status = self.status()
        if status.state in ('pause', 'stop'):
            return Attrs(playlist[int(status.song)])
        if cur is None:
            return Attrs(playlist[0])
        else:
            try:
                return Attrs(playlist[int(cur.pos)+1])
            except IndexError:
                return None

    def playnow(self, song):
        self.playnext(song)
        self.__client.next()

    # insert as the next song after the current one
    def playnext(self, song):
        status = self.status()
        if status.state == "stop":
            self.__client.play()
        songid = self.__client.addid(song.file)
        if int(status.song) < (int(status.playlistlength)-1):
            self.__client.moveid(songid, int(status.song)+1)

    # add a song at end of playlist, return the number of songs to play before
    # playing the one just added, including the current (so 1 would mean it's
    # the next song etc)
    def playlater(self, song):
        status = self.status()
        if status.state == "stop":
            self.__client.play()
        self.__client.add(song.file)
        status = self.status()
        return int(status.playlistlength) - int(status.song) - 1

    def delnext(self):
        status = self.status()
        if status.state == "stop":
            return
        self.__client.delete(int(status.song)+1)

    def setvol(self, volume):
        self.__client.setvol(volume)

    def search(self, text):
        def searchpred(text, song):
            try:
                return text.lower() in songrepr(song).lower()
            except AttributeError:
                return False
        what_to_search = self.library
        if self.last_search_string is not None and \
                text.startswith(self.last_search_string) and \
                len(text) > len(self.last_search_string):
            what_to_search = self.last_search_results
        results = [song for song in what_to_search if searchpred(text, song)]
        if conf.SORT_SEARCH:
            results = sorted(results, cmp=lambda a, b: cmp(songrepr(a), songrepr(b)))
        self.last_search_string = text
        self.last_search_results = results
        return results

    def serversearch(self, text):
        return [Attrs(song) for song in self.__client.search("any", text)]
